﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace RaisingStudio.SmallProgram.Library
{
    [SmallProgramType]
    public static class Shapes
    {
        private static Dictionary<string, int> _nameGenerationMap = new Dictionary<string, int>();
        private static Dictionary<string, Point> _positionMap = new Dictionary<string, Point>();
        private static Dictionary<string, RotateTransform> _rotateTransformMap = new Dictionary<string, RotateTransform>();
        private static Dictionary<string, ScaleTransform> _scaleTransformMap = new Dictionary<string, ScaleTransform>();

        internal static string GenerateNewName(string prefix)
        {
            int num = 0;
            _nameGenerationMap.TryGetValue(prefix, out num);
            num++;
            _nameGenerationMap[prefix] = num;
            return (prefix + num.ToString());
        }

        public static Primitive AddEllipse(Primitive width, Primitive height)
        {
            string name = GenerateNewName("Ellipse");
            GraphicsWindow.Invoke(delegate
            {
#if SILVERLIGHT
                Ellipse shape = new Ellipse();
                GraphicsWindow.AddShape(name, shape);
                shape.Width = (double) width;
                shape.Height = (double) height;
                shape.Fill = GraphicsWindow._fillBrush;
                shape.Stroke = GraphicsWindow._pen.Brush;
                shape.StrokeThickness = GraphicsWindow._pen.Thickness;
#else
                GraphicsWindow.VerifyAccess();
                Ellipse shape = new Ellipse
                {
                    Width = (double)width,
                    Height = (double)height,
                    Fill = GraphicsWindow._fillBrush,
                    Stroke = GraphicsWindow._pen.Brush,
                    StrokeThickness = GraphicsWindow._pen.Thickness
                };
                GraphicsWindow.AddShape(name, shape);
#endif
            });
            return name;
        }

        public static Primitive AddImage(Primitive imageName)
        {
            string name = GenerateNewName("Image");
            GraphicsWindow.Invoke(delegate
            {
                Image shape = new Image();
                BitmapSource bitmap = ImageList.GetBitmap(imageName);
                if (bitmap != null)
                {
                    shape.Source = bitmap;
                    if ((bitmap.PixelWidth != 0) && (bitmap.PixelHeight != 0))
                    {
                        shape.Width = bitmap.PixelWidth;
                        shape.Height = bitmap.PixelHeight;
                    }
                    GraphicsWindow.AddShape(name, shape);
                }
            });
            return name;
        }

        public static Primitive AddLine(Primitive x1, Primitive y1, Primitive x2, Primitive y2)
        {
            string name = GenerateNewName("Line");
            GraphicsWindow.Invoke(delegate
            {
                Line shape = new Line();
                GraphicsWindow.AddShape(name, shape);
                shape.X1 = (double)x1;
                shape.Y1 = (double)y1;
                shape.X2 = (double)x2;
                shape.Y2 = (double)y2;
                shape.Stroke = GraphicsWindow._pen.Brush;
                shape.StrokeThickness = GraphicsWindow._pen.Thickness;
            });
            return name;
        }

        public static Primitive AddRectangle(Primitive width, Primitive height)
        {
            string name = GenerateNewName("Rectangle");
            GraphicsWindow.Invoke(delegate
            {
#if SILVERLIGHT
                Rectangle shape = new Rectangle();
                GraphicsWindow.AddShape(name, shape);
                shape.Width = (double) width;
                shape.Height = (double) height;
                shape.Fill = GraphicsWindow._fillBrush;
                shape.Stroke = GraphicsWindow._pen.Brush;
                shape.StrokeThickness = GraphicsWindow._pen.Thickness;
#else
                GraphicsWindow.VerifyAccess();
                Rectangle shape = new Rectangle
                {
                    Width = (double)width,
                    Height = (double)height,
                    Fill = GraphicsWindow._fillBrush,
                    Stroke = GraphicsWindow._pen.Brush,
                    StrokeThickness = GraphicsWindow._pen.Thickness
                };
                GraphicsWindow.AddShape(name, shape);
#endif
            });
            return name;
        }

        public static Primitive AddText(Primitive text)
        {
            string name = GenerateNewName("Text");
            GraphicsWindow.Invoke(delegate
            {
                TextBlock shape = new TextBlock
                {
                    Text = text,
                    Foreground = GraphicsWindow._fillBrush,
                    FontFamily = GraphicsWindow._fontFamily,
                    FontStyle = GraphicsWindow._fontStyle,
                    FontSize = GraphicsWindow._fontSize,
                    FontWeight = GraphicsWindow._fontWeight
                };
                GraphicsWindow.AddShape(name, shape);
            });
            return name;
        }

        public static Primitive AddTriangle(Primitive x1, Primitive y1, Primitive x2, Primitive y2, Primitive x3, Primitive y3)
        {
            string name = GenerateNewName("Triangle");
            GraphicsWindow.Invoke(delegate
            {
                Polygon shape = new Polygon();
                GraphicsWindow.AddShape(name, shape);
                shape.Points.Add(new Point((double)x1, (double)y1));
                shape.Points.Add(new Point((double)x2, (double)y2));
                shape.Points.Add(new Point((double)x3, (double)y3));
                shape.Fill = GraphicsWindow._fillBrush;
                shape.Stroke = GraphicsWindow._pen.Brush;
                shape.StrokeThickness = GraphicsWindow._pen.Thickness;
            });
            return name;
        }

        public static void Remove(Primitive shapeName)
        {
            GraphicsWindow.RemoveShape(shapeName);
        }


        public static void Animate(Primitive shapeName, Primitive x, Primitive y, Primitive duration)
        {
            UIElement obj;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out obj))
            {
                _positionMap[(string)shapeName] = new Point((double)x, (double)y);
                GraphicsWindow.Invoke(delegate
                {
                    GraphicsWindow.DoubleAnimateProperty(obj, Canvas.LeftProperty, (double)x, (int)duration);
                    GraphicsWindow.DoubleAnimateProperty(obj, Canvas.TopProperty, (double)y, (int)duration);
                });
            }
        }


        public static Primitive GetLeft(Primitive shapeName)
        {
            UIElement element;
            Point point;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element) && _positionMap.TryGetValue((string)shapeName, out point))
            {
                return point.X;
            }
            return 0;
        }

        public static Primitive GetTop(Primitive shapeName)
        {
            UIElement element;
            Point point;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element) && _positionMap.TryGetValue((string)shapeName, out point))
            {
                return point.Y;
            }
            return 0;
        }

        public static void SetText(Primitive shapeName, Primitive text)
        {
            UIElement element;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element))
            {
                TextBlock textBlock = element as TextBlock;
                if (textBlock != null)
                {
                    GraphicsWindow.BeginInvoke(delegate
                    {
                        textBlock.Text = (string)text;
                    });
                }
            }
        }

        public static Primitive GetOpacity(Primitive shapeName)
        {
            UIElement element;
            if (!GraphicsWindow._objectsMap.TryGetValue(shapeName, out element))
            {
                return 0;
            }
            return (Primitive)GraphicsWindow.InvokeWithReturn(delegate
            {
                return element.Opacity * 100.0;
            });
        }

        public static void SetOpacity(Primitive shapeName, Primitive level)
        {
            UIElement element;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element))
            {
                GraphicsWindow.Invoke(delegate
                {
                    element.Opacity = (double)(RaisingStudio.SmallProgram.Library.Math.Min(100, RaisingStudio.SmallProgram.Library.Math.Max(0, level)) / 100);
                });
            }
        }


        public static void ShowShape(Primitive shapeName)
        {
            UIElement element;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element))
            {
                GraphicsWindow.Invoke(delegate
                {
                    element.Visibility = Visibility.Visible;
                });
            }
        }

        public static void HideShape(Primitive shapeName)
        {
            UIElement element;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element))
            {
                GraphicsWindow.Invoke(delegate
                {
                    element.Visibility = Visibility.Collapsed;
                });
            }
        }

        public static void Move(Primitive shapeName, Primitive x, Primitive y)
        {
            UIElement element;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element))
            {
                _positionMap[(string)shapeName] = new Point((double)x, (double)y);
                GraphicsWindow.BeginInvoke(delegate
                {
                    element.BeginAnimation(Canvas.LeftProperty, null);
                    element.BeginAnimation(Canvas.TopProperty, null);
                    Canvas.SetLeft(element, (double)x);
                    Canvas.SetTop(element, (double)y);
                });
            }
        }

        public static void Rotate(Primitive shapeName, Primitive angle)
        {
            UIElement element;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element))
            {
                GraphicsWindow.BeginInvoke(delegate
                {
                    RotateTransform transform;
                    if (!(element.RenderTransform is TransformGroup))
                    {
                        element.RenderTransform = new TransformGroup();
                    }
                    if (!_rotateTransformMap.TryGetValue((string)shapeName, out transform))
                    {
                        transform = new RotateTransform();
                        _rotateTransformMap[(string)shapeName] = transform;
                        FrameworkElement frameworkElement = element as FrameworkElement;
                        if (frameworkElement != null)
                        {
                            transform.CenterX = frameworkElement.ActualWidth / 2.0;
                            transform.CenterY = frameworkElement.ActualHeight / 2.0;
                        }
                        ((TransformGroup)element.RenderTransform).Children.Add(transform);
                    }
                    transform.Angle = (double)angle;
                });
            }
        }

        public static void Zoom(Primitive shapeName, Primitive scaleX, Primitive scaleY)
        {
            UIElement element;
            if (GraphicsWindow._objectsMap.TryGetValue(shapeName, out element))
            {
                scaleX = Math.Min(Math.Max(scaleX, 0.1), 20.0);
                scaleY = Math.Min(Math.Max(scaleY, 0.1), 20.0);
                GraphicsWindow.BeginInvoke(delegate
                {
                    ScaleTransform transform;
                    if (!(element.RenderTransform is TransformGroup))
                    {
                        element.RenderTransform = new TransformGroup();
                    }
                    if (!_scaleTransformMap.TryGetValue((string)shapeName, out transform))
                    {
                        transform = new ScaleTransform();
                        _scaleTransformMap[(string)shapeName] = transform;
                        FrameworkElement frameworkElement = element as FrameworkElement;
                        if (frameworkElement != null)
                        {
                            transform.CenterX = frameworkElement.ActualWidth / 2.0;
                            transform.CenterY = frameworkElement.ActualHeight / 2.0;
                        }
                        ((TransformGroup)element.RenderTransform).Children.Add(transform);
                    }
                    transform.ScaleX = (double)scaleX;
                    transform.ScaleY = (double)scaleY;
                });
            }
        }
    }
}

